#ifndef __BASE_ARRAY_H__
#define __BASE_ARRAY_H__

#include "typedef.h"

#include <stdlib.h>

namespace base {
  // array must be pointer
  template <typename T>
  class array {
    public:
      array() : allocated_(0), size_(0), datas_(0) { clear(); }
      ~array() { clear(); }
      array(const array<T>& other) { deep_copy(other); }
      array<T>& operator = (const array<T>& other) { deep_copy(other); return *this; }
      void deep_copy(const array& other) {
        reserve(other.allocated_);
        size_ = other.size_;
        ::memcpy(datas_, other.datas_, size_);
      }
      void swap(array<T> *other) {
        if (!other) return;
        uint allocated = allocated_; allocated_ = other->allocated_; other->allocated_ = allocated;
        uint size = size_; size_ = other->size_; other->size_ = size;
        T *datas = datas_; datas_ = other->datas_; other->datas_ = datas;
      }
      void clear() {
        if (datas_) { ::free(datas_); datas_ = 0; }
        allocated_ = 0; size_ = 0;
      }
    public:
      uint capacity() const { return allocated_; }
      uint reserve(uint n = 0) {
        if (n < size_) n = size_;
        if (n <= allocated_) return allocated_;
        datas_ = (T*)::realloc(datas_, sizeof(T) * n);
        allocated_ = n;
        return allocated_;
      }
    public:
      void add(T d) { add_at(d, size_); }
      void add_at(T d, uint idx) {
        reserve(size_+1);
        for (uint i = size_; i > idx; --i) {
          datas_[i] = datas_[i-1];
        }
        datas_[idx] = d;
        ++size_;
      }
      void erase(T d) { erase(index(d)); }
      void erase(uint idx) {
        if (idx >= size_) return;
        --size_;
        for (uint i = idx; i < size_; ++i) {
          datas_[i] = datas_[i+1];
        }
      }
      void erase_all() { size_ = 0; }
      T at(uint idx) const {
        if (idx >= size_) return 0;
        return datas_[idx];
      }
      uint index(T d) {
        for (uint i = 0; i < size_; ++i) {
          if (datas_[i] == d) return i;
        }
        return npos;
      }
      uint size() const { return size_; }
    protected:
      uint allocated_;
      uint size_;
      T *datas_;
  };
} // end namespace base

#endif // __BASE_ARRAY_H__